package communication.common.business.base;

import io.vertx.core.json.JsonObject;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mac
 */
@Slf4j
public  abstract class CommonBaseHandler implements ModuleHandler{

    private  Map<Integer, Map<String, MethodMap>> methodMap =null;

    public CommonBaseHandler(){
        methodMap=new HashMap<>();
        methodMap.put(0,new HashMap<>());
        methodMap.put(1,new HashMap<>());
    }


    public void addMethodMap(MethodMap methodMap) throws Exception {
        if(this.methodMap.get(methodMap.getType()).containsKey(methodMap.getOp())){
            throw new Exception("repeated op:"+methodMap.getOp());
        }

        this.methodMap.get(methodMap.getType()).put(methodMap.getOp(),methodMap);
    }


    public MethodMap getMethodMap(String op,int type){
        return this.methodMap.get(type).get(op);
    }

    @Override
    public Object doBusiness(MsgData obj , String remoteSocketAddress) throws Exception {
        Object result=null;
        // 从bean中找到对应的method、入参类型、返回值类型
        MethodMap methodMap = getMethodMap(obj.getOp(),obj.getType());

        if(methodMap==null){
            return ResponseDto.fail(999,"can not location method! op:"+obj.getOp() +", type:"+obj.getType());
        }

        Object bean = methodMap.getServiceBean();

        Method method = bean.getClass().getMethod(methodMap.getMethodName(), methodMap.getRequestClassList());

        if(method==null){
            return ResponseDto.fail(999,"can not location method! methodName :"+methodMap.getMethodName());
        }

        // 方法定义的入参个数
        int argSize = methodMap.getRequestClassList().length;

        Object[] args  = new Object[argSize];

        // 是否需要设置 remoteSocketAddress的标识
        boolean setRemoteSocketAddressFlg = false;

        // 是请求类型，设置入参
        if(obj.getType()==0){
            setRemoteSocketAddressFlg = needSetRemoteSocketAddress(argSize, obj.getOpParam(), method.getParameterTypes());

            setArgsOnRequest(argSize ,obj,args ,methodMap, method,remoteSocketAddress);
        }else {
            // 是响应类型，设置入参

            Object[] params ={obj.getResponse()};

            setRemoteSocketAddressFlg = needSetRemoteSocketAddress(argSize,params , method.getParameterTypes());

            setArgsOnResponse(argSize ,obj,args,methodMap);
        }

        // 设置 remoteSocketAddress
        if(setRemoteSocketAddressFlg){
            FcrSocketAddress socketAddress = FcrSocketAddress.getByString(remoteSocketAddress);
            args[argSize-1]=socketAddress;
        }

        result = method.invoke(bean, args);

        return result;
    }

    private void setArgsOnResponse(int argSize, MsgData obj, Object[] args, MethodMap methodMap) throws Exception {

        // 将obj的response转换为method需要的入参
         if (argSize > 0 ){
             if(obj.getResponse()==null){
                 throw new Exception("msgData.opParam.size() can not match method.param.size() ！");
             }

             if(obj.getResponse() instanceof  JsonObject){
                 args[0]=((JsonObject)obj.getResponse()).mapTo(methodMap.getRequestClassList()[0]);
             }else{
                 args[0]=obj.getResponse();
             }

         }

    }

    private void setArgsOnRequest(int argSize, MsgData obj, Object[] args, MethodMap methodMap, Method method, String remoteSocketAddress) throws Exception {

        // 需要的参数数量不为0
        if(argSize > 0 ){

            if(obj.getOpParam().length == 0){
                throw new Exception("msgData.opParam.size() can not match method.param.size() ！");
            }

            for(int i=0;i< obj.getOpParam().length;i++){
                if(obj.getOpParam()[i] instanceof  JsonObject){
                    args[i]=((JsonObject)obj.getOpParam()[i]).mapTo(methodMap.getRequestClassList()[i]);
                }else{
                    args[i]=obj.getOpParam()[i];
                }
            }


        }

    }

    private ResponseDto getNotMatchResponseDto(){
        String errMsg="msgData.opParam.size() can not match method.param.size() ！";
        log.error(errMsg);
        return ResponseDto.fail(999,errMsg);
    }

    /**
     * 判断是否需要设置远程socket到入参中;
     *   如果入参列表比传入参数多一个，且是String类型，且入参名称叫 remoteSocketAddress,则返回true
     * @param argSize
     * @param params
     * @param paramTypes
     * @return
     */
    private boolean needSetRemoteSocketAddress(int argSize ,Object[] params, Class<?>[] paramTypes){
        if(argSize>0
                && params!=null
                && argSize==params.length+1
                && paramTypes[argSize-1].equals(FcrSocketAddress.class)){
            return true;
        }
        return false;
    }

}
